﻿/* 
 * Copyright 2010 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License")
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using log4net;
using Ngilead.Core.Store;
using Ngilead.Core.Utils;
using System.Threading;
using Ngilead.Core.Replicator;
using Ngilead.Core.Replicator.Clone;
using Ngilead.Core.Replicator.Merge;

namespace Ngilead.Core
{
    /// <summary>
    /// Lazy killer class
    /// </summary>
    public class LazyKiller
    {
        #region Attributes

        /// <summary>
        /// Logger channel
        /// </summary>
        private static ILog logger = LogManager.GetLogger(typeof(LazyKiller));

        #endregion

        #region Public properties
        /// <summary>
        /// The associated persistence utils
        /// </summary>
        public IPersistenceUtil PersistenceUtil { get; set; }

        /// <summary>
        /// The used proxy store
        /// </summary>
        public IProxyStore ProxyStore { get; set; }

        #endregion

        #region Ctor

        /// <summary>
        /// Empty constructor
        /// </summary>
        public LazyKiller()
            : this(null, null)
        {
        }

        /// <summary>
        /// Base constructor
        /// </summary>
        /// <param name="persistenceUtil">persistence util implementation</param>
        /// <param name="proxyStore">the proxy store</param>
        public LazyKiller(IPersistenceUtil persistenceUtil,
                          IProxyStore proxyStore)
        {
            PersistenceUtil = persistenceUtil;
            ProxyStore = proxyStore;
        }

        #endregion

        #region Public interface

        /// <summary>
        /// Hibernate detachment
        /// </summary>
        /// <param name="hibernatePojo">the input hibernate pojo</param>
        /// <returns>a pure Java clone</returns>
        public object Detach(object hibernatePojo)
        {
            // Precondition checking
            if (hibernatePojo == null)
            {
                return null;
            }

            if (logger.IsInfoEnabled)
            {
                logger.Info("Detach(hibernatePojo)");
            }

            return Clone(hibernatePojo);
        }

        /// <summary>
        /// Hibernate attachment
        /// </summary>
        /// <param name="clonePojo">the cloned pojo</param>
        public Object Attach(Object clonePojo)
        {
            //	Precondition checking
            if (clonePojo == null)
            {
                return null;
            }

            if (logger.IsInfoEnabled)
            {
                logger.Info("Attach(clonePojo)");
            }

            //	Populate
            return Merge(clonePojo);
        }

        #endregion

        #region Internal methods

        /// <summary>
        /// Clone the persistent entity to a pure POCO
        /// Every time a lazy property is detected, it is replaced with null.
        /// It is also marked as "lazy" for ILightEntity sub-classes
        /// </summary>
        /// <param name="hibernatePojo"></param>
        /// <returns></returns>
        protected object Clone(Object hibernatePojo)
        {
            if (logger.IsInfoEnabled)
            {
                logger.Info("Clone(hibernatePojo)");
            }
            
            //  Init transformer
            //
            BeanTransformer transformer = new BeanTransformer();

            // Clone collection replicator
            CloneCollectionReplicator collectionReplicator = new CloneCollectionReplicator();
            collectionReplicator.PersistenceUtil = PersistenceUtil;
            transformer.CollectionReplicator = collectionReplicator;

            // Set collection replicator
            CloneSetReplicator setReplicator = new CloneSetReplicator();
            setReplicator.PersistenceUtil = PersistenceUtil;
            transformer.SetReplicator = setReplicator;

            // Clone instance replicator
            CloneInstanceReplicator instanceReplicator = new CloneInstanceReplicator();
            instanceReplicator.PersistenceUtil = PersistenceUtil;
            transformer.InstanceReplicator = instanceReplicator;

            // Dictionary replicator
            CloneDictionaryReplicator dictionaryReplicator = new CloneDictionaryReplicator();
            dictionaryReplicator.PersistenceUtil = PersistenceUtil;
            transformer.DictionaryReplicator = dictionaryReplicator;

            // Clone property filter
            ClonePropertyFilter propertyFilter = new ClonePropertyFilter();
            propertyFilter.PersistenceUtil = PersistenceUtil;
            propertyFilter.ProxyStore = ProxyStore;
            transformer.PropertyFilter = propertyFilter;

            //  Replicate entity
            //
            return transformer.Replicate(hibernatePojo);
        }

        /// <summary>
        /// Merge the clonePojo to a valid persistent entity
        /// </summary>
        /// <param name="clonePojo"></param>
        public Object Merge(Object clonePojo)
        {
            if (logger.IsInfoEnabled)
            {
                logger.Info("Merge(clonePojo)");
            }

            //  Init replicator
            //
            BeanTransformer transformer = new BeanTransformer();

            // Merge collection replicator
            MergeCollectionReplicator collectionReplicator = new MergeCollectionReplicator();
            collectionReplicator.PersistenceUtil = PersistenceUtil;
            transformer.CollectionReplicator = collectionReplicator;

            // Merge collection replicator
            MergeSetReplicator setReplicator = new MergeSetReplicator();
            setReplicator.PersistenceUtil = PersistenceUtil;
            transformer.SetReplicator = setReplicator;

            // Merge Dictionary replicator
            MergeDictionaryReplicator dictionaryReplicator = new MergeDictionaryReplicator();
            dictionaryReplicator.PersistenceUtil = PersistenceUtil;
            transformer.DictionaryReplicator = dictionaryReplicator;

            // Instance replicator
            transformer.InstanceReplicator = new InstanceReplicator();

            // Merge property filter
            MergePropertyFilter propertyFilter = new MergePropertyFilter(transformer, PersistenceUtil, ProxyStore);
            transformer.PropertyFilter = propertyFilter;

            //  Replicate pojo
            //
            Object result = transformer.Replicate(clonePojo);

            return result;
        }

        #endregion
        /*----------------------------------------------------------------------------------------*/
    }
}
